﻿using CQRSFramework.Common.Components;
using CQRSFramework.Common.Serializer;
using CQRSFramework.Events;
using CQRSFramework.Infrustructures;
using CQRSFramework.Messages;
using RabbitMQ.Client;
using RabbitMQ.Client.Events;
using System;
using System.Text;

namespace CQRSFramework.RabbitMQ
{
    public class EventConsumer : IDisposable
    {
        private const string BORKER_NAME = "CQRSFramework";
        
        private readonly ITypeNameProvider _typeNameProvider;
        private readonly IJsonSerializer _jsonSerializer;
        private readonly IRabbitMQPersistentConnection _rabbitMQPersistentConnection;
        private readonly IEventProcess _eventProcess;
        private IModel _channel;
        public EventConsumer()
        {
            _typeNameProvider = ObjectContainer.Resolve<ITypeNameProvider>();
            _jsonSerializer = ObjectContainer.Resolve<IJsonSerializer>();
            _rabbitMQPersistentConnection = ObjectContainer.Resolve<IRabbitMQPersistentConnection>();
            _eventProcess = ObjectContainer.Resolve<IEventProcess>();
        }
        public void Subscribe(string routingKey)
        {
            if (!_rabbitMQPersistentConnection.IsConnected)
            {
                _rabbitMQPersistentConnection.TryConnect();
            }
            _channel = _rabbitMQPersistentConnection.CreateModel();
            _channel.ExchangeDeclare(exchange: BORKER_NAME, type: "topic", durable: true, autoDelete: false, arguments: null);
            var queueName = _channel.QueueDeclare(queue: routingKey, durable: true, exclusive: false, autoDelete: false, arguments: null).QueueName;
            _channel.QueueBind(queue: queueName, exchange: BORKER_NAME, routingKey: routingKey, arguments: null);
            var consumer = new EventingBasicConsumer(_channel);
            consumer.Received += Consumer_Received;
            _channel.BasicConsume(queue: queueName, autoAck: false, consumer: consumer);
        }

        private void Consumer_Received(object sender, BasicDeliverEventArgs ea)
        {
            var message = Encoding.UTF8.GetString(ea.Body);
            var msg = _jsonSerializer.Deserialize<QueueMessage>(message);
            var evnt = _jsonSerializer.Deserialize<IDomainEvent>(msg.Body, _typeNameProvider.Get(msg.TypeName));
            _eventProcess.Process(evnt, _channel, ea);
        }
        public void Dispose()
        {
            if (_channel != null)
                _channel.Dispose();
        }
    }
}
